package com.example.literj.kt.core

import com.example.literj.kt.internal.operators.single.SingleJust
import com.example.literj.kt.internal.operators.single.SingleMap
import com.example.literj.kt.internal.operators.single.SingleObserveOn
import com.example.literj.kt.internal.operators.single.SingleSubscribeOn
import com.example.literj.kt.plugins.RxJavaPlugins
import java.util.*

abstract class Single<T> : SingleSource<T> {
    companion object {
        @JvmStatic
        fun <T> just(item: T): Single<T> {
            return RxJavaPlugins.onAssembly(SingleJust(item))
        }
    }

    fun <R> map(mapper: com.example.literj.kt.internal.functions.Function<in T, out R>): Single<R> {
        Objects.requireNonNull(mapper, "mapper is null")
        return RxJavaPlugins.onAssembly(SingleMap(this, mapper))
    }

    fun subscribeOn(scheduler: Scheduler): Single<T> {
        Objects.requireNonNull(scheduler, "scheduler is null")
        return RxJavaPlugins.onAssembly(SingleSubscribeOn(this, scheduler))
    }

    fun observeOn(scheduler: Scheduler): Single<T> {
        Objects.requireNonNull(scheduler, "scheduler is null")
        return RxJavaPlugins.onAssembly(SingleObserveOn(this, scheduler))
    }

    override fun subscribe(observer: SingleObserver<in T>) {
        Objects.requireNonNull(observer, "observer is null")

        try {
            var obsv = observer
            obsv = RxJavaPlugins.onSubscribe(this, obsv)
            subscribeActual(obsv)
        } catch (e: NullPointerException) {
            throw e
        } catch (e: Throwable) {
            throw NullPointerException("subscribeActual failed").initCause(e)
        }
    }

    protected abstract fun subscribeActual(observer: SingleObserver<in T>)
}